#ifndef __VAP_UTILS__
#define __VAP_UTILS__

#include <unistd.h>
#include <string>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <sstream>
#include <chrono> 
#include <iostream>
#include <fstream>
#include <iomanip>
#include <thread>
#include <stdexcept>

#include <stdarg.h>

namespace vap_utils{

    // 日志等级
    enum LOG_LEVEL{
        DEBUG,      // 0
        INFO,       // 1
        WARN,       // 2
        ERROR,      // 3
        CRITICAL    // 4
    };

    /**
     * 类名： 信号量
     * 描述：
     *      C++ 20 中才包含了信号量，因此这里使用互斥锁和条件变量进行实现
     */ 
    class vap_semaphore
    {
    public:
        vap_semaphore(){};
        ~vap_semaphore(){};
        void signal(){
            std::unique_lock<std::mutex> lock(mutex_);
            ++count_;
            cv_.notify_one();
        };
        void wait()
        {   
            std::unique_lock<std::mutex> lock(mutex_);
            cv_.wait(lock, [=] { return count_ > 0; });
            --count_;
        };
    private:
        std::mutex mutex_;
        std::condition_variable cv_;
        int count_; 
    };
    /**
     * 类型：vap_gate
     * 描述：每条流水线最开始运行的开关
    */
    class vap_gate
    {
    public:
        vap_gate() {
            opened_ = false;
        }

        void open() {
            std::unique_lock<std::mutex> lock(mutex_);
            opened_ = true;
            cv_.notify_one();
        }

        // wait until opened
        void knock() {
            std::unique_lock<std::mutex> lock(mutex_);
            cv_.wait(lock, [=] { return opened_; });
        }

        void close() {
            std::unique_lock<std::mutex> lock(mutex_);
            opened_ = false;
        }

    private:
        std::mutex mutex_;
        std::condition_variable cv_;
        bool opened_;
    };
    /**
     * 类名：日志工具
     * 描述：  
     *      * 经典的单例模式
     * 
     */
    class vaplog
    {
    private:
        vaplog():init_flag_(false),cache_maxsize_(64),log2console_(true),log2file_(true),log2file_path_("./"), \
            log2file_filename_("log"),log_level_(DEBUG),enable_code_file_(true),enable_code_line_(false), \
            enable_code_func_(true){
                // auto t = std::thread(log_run_back,this); // 在构造函数中自动创建后台线程
                // log_writer_th = std::move(t);
            }; // 单例模式，禁止显式构造

        int log_level_; // 默认日志等级为1，大于等于log_level的日志将被输出
        std::queue<std::string> log_queue_;
        class vap_semaphore log_queue_semaphore_; // 保证日志队列的线程安全
        std::mutex log_queue_mutex; // 日志缓存互斥锁
        bool init_flag_;    //初始化标志
        int cache_maxsize_;     //日志最大缓存
        bool log2console_;      //是否打印输出到终端
        bool log2file_;         //是否打印输出到文件
        bool enable_code_file_;     // 是否使能打印信息包含文件
        bool enable_code_line_;     // 是否使能打印信息包含行
        bool enable_code_func_;     // 是否使能打印信息包含函数
        std::fstream file_writer_;  // 日志信息输出到文件
        std::string log2file_path_;    // 日志路径
        std::string log2file_filename_;     // 日志名称
        std::thread log_writer_th_;         // 后台写线程号


        /**
         * 后台线程处理日志队列的打印
        */
        void  log_run_back()
        {
            while (this->init_flag_)
            {
                this->log_queue_semaphore_.wait();
                auto log = log_queue_.front();
                log_queue_.pop();

                if (this->log2console_) {
                    write_to_console(log);
                }
                if(this->log2file_)
                {
                    write_to_file(log);
                }
            }
        }

        void write_to_console(const std::string& log)
        {
            std::cout << log << std::endl;
        }
        
        void createlogfile()
        {
            
                // 创建日志文件 
                auto now = std::chrono::system_clock::now();
                std::time_t time = std::chrono::system_clock::to_time_t(now);
                std::stringstream filename;
                filename << log2file_filename_;
                filename << std::put_time(std::localtime(&time), "_%Y%m%d%H%M%S");
                filename << ".log";
                std::cout<<log2file_path_+filename.str()<<std::endl;
                file_writer_.open(log2file_path_+filename.str(), std::ios::ate | std::ios::out);
                if(!file_writer_.is_open())
                    std::cout<< "Please check log path is correct"<<std::endl;

        }
        void checklogfilesize()
        {
            std::streampos fileSize = file_writer_.tellg();
            if(fileSize > 2*1024*1024-1)  // 日志文件的大小限制在2M,当超过则新建一个文件
            {
                file_writer_.close();
                createlogfile(); // 日志文件超过1M,新建一个新的日志文件
            }
        }

        void write_to_file(const std::string& log)
        {
            file_writer_ << log;
            file_writer_ << "\r\n";
            file_writer_.flush();
            checklogfilesize();
        }

    public:
        vaplog(const vaplog&) =delete;    //单例模式，禁止拷贝构造
        vaplog& operator=(const vaplog&) =delete; //单例模式，禁止拷贝赋值

        /**
         * 局部静态变量的懒汉单例，可以保证线程安全
         * 静态局部变量初始化一次，并一直保存在内存中，但其作用域只在函数体内
         * 只能由静态函数进行访问
         */
        static vaplog& getlogger()  
        {
            static class vaplog logger;
            return logger;
        }
        void set_level(int log_level)
        {
            this->log_level_ = log_level;
        }
        void set_cache_maxsize(int cache_maxsize)
        {
            this->cache_maxsize_ = cache_maxsize;
        }
        void set_log2console(bool flag)
        {
            this->log2console_ = flag;
        }
        void set_log2file(bool flag)
        {
            this->log2file_ = flag;
        }
        void set_log2file_path(const std::string& path)
        {
            this->log2file_path_ = path;
        }
        void set_log2file_filename(const std::string& filename)
        {
            this->log2file_filename_ = filename;
        }
        void set_code_file(bool flag)
        {
            this->enable_code_file_ = flag;
        }
        void set_code_line(bool flag)
        {
            this->enable_code_line_ = flag;
        }
        void set_code_func(bool flag)
        {
            this->enable_code_func_= flag;
        }

        void init()
        {
            init_flag_ = true;
            if(log2file_)
                createlogfile();  //追加模式

            auto t = std::thread(&vaplog::log_run_back,this); // 在构造函数中自动创建后台线程
            log_writer_th_ = std::move(t);
        }

        void log(LOG_LEVEL log_level,const char* code_file, int code_line,const char* func,const char* format, ...)
        {
            if(this->init_flag_ !=  true)
                return ;

             // 获取当前时间
            auto now = std::chrono::system_clock::now();
            std::time_t time = std::chrono::system_clock::to_time_t(now);

            // 使用 std::stringstream 格式化日志信息
            std::stringstream logStream;
            logStream << std::put_time(std::localtime(&time), "[%Y-%m-%d %H:%M:%S] ");

            if(log_level < this->log_level_)
                return; 

            if(enable_code_file_)
                logStream<< "["+std::string(code_file)+"] ";
            if(enable_code_func_)
                logStream<< "["+std::string(func)+"] ";    
            if(enable_code_line_)
                logStream<< "["+std::to_string(code_line)+"] ";

            switch (log_level) {
                case LOG_LEVEL::DEBUG:
                    logStream << "[DEBUG] ";
                    break;
                case LOG_LEVEL::INFO:
                    logStream << "[INFO] ";
                    break;
                case LOG_LEVEL::WARN:
                    logStream << "[WARN] ";
                    break;
                case LOG_LEVEL::ERROR:
                    logStream << "[ERROR] ";
                    break;
                case LOG_LEVEL::CRITICAL:
                    logStream << "[CRITICAL] ";
                    break;
            }
            logStream <<": ";

            // 使用 __VA_ARGS__ 宏将可变参数格式化到日志流中
            va_list args;
            va_start(args, format);
            char buffer[1024];
            vsnprintf(buffer, sizeof(buffer) - 1, format, args);
            va_end(args);

            logStream << buffer;

            std::lock_guard<std::mutex> guard(log_queue_mutex); // lock_guard 类型
            log_queue_.push(logStream.str());
            log_queue_semaphore_.signal();
        }

        ~vaplog() {}; 
    };
}


#define VAP_LOG_SET_LEVEL(level)  vap_utils::vaplog::getlogger().set_level(level)
#define VAP_LOG_SET_CACHESIZE(size)  vap_utils::vaplog::getlogger().set_cache_maxsize(size)
#define VAP_LOG_ENABLE_CONSOLE(flag)  vap_utils::vaplog::getlogger().set_log2console(flag)
#define VAP_LOG_ENABLE_FILE(flag)  vap_utils::vaplog::getlogger().set_log2file(flag)
#define VAP_LOG_ENABLE_CODE_FILE(flag)  vap_utils::vaplog::getlogger().set_code_file(flag)
#define VAP_LOG_ENABLE_CODE_LINE(flag)  vap_utils::vaplog::getlogger().set_code_line(flag)
#define VAP_LOG_ENABLE_CODE_FUNC(flag)  vap_utils::vaplog::getlogger().set_code_func(flag)
#define VAP_LOG_SET_LOGFILE_PATH(path)  vap_utils::vaplog::getlogger().set_log2file_path(path)
#define VAP_LOG_SET_LOGFILE_NAME(name)  vap_utils::vaplog::getlogger().set_log2file_filename(name)

#define VAP_LOG_INIT() vap_utils::vaplog::getlogger().init()

#define VAP_LOG_INFO(format,...) vap_utils::vaplog::getlogger().log(vap_utils::LOG_LEVEL::INFO,__FILE__,__LINE__,__FUNCTION__,format,##__VA_ARGS__)
#define VAP_LOG_DEBUG(format,...) vap_utils::vaplog::getlogger().log(vap_utils::LOG_LEVEL::DEBUG,__FILE__,__LINE__,__FUNCTION__,format,##__VA_ARGS__)
#define VAP_LOG_WARN(format,...) vap_utils::vaplog::getlogger().log(vap_utils::LOG_LEVEL::WARN,__FILE__,__LINE__,__FUNCTION__,format,##__VA_ARGS__)
#define VAP_LOG_ERROR(format,...) vap_utils::vaplog::getlogger().log(vap_utils::LOG_LEVEL::ERROR,__FILE__,__LINE__,__FUNCTION__,format,##__VA_ARGS__)
#define VAP_LOG_ECRITICAL(format,...) vap_utils::vaplog::getlogger().log(vap_utils::LOG_LEVEL::CRITICAL,__FILE__,__LINE__,__FUNCTION__,format,##__VA_ARGS__)

#endif // __VAP_UTILS__